﻿using ICSharpCode.WinFormsUI.Controls.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms; 

namespace ICSharpCode.WinFormsUI.Controls
{
    /// <summary>
    /// 名称：下载列表 
    /// 版本：NDownList V 1.0.2
    /// 作者：王晓东
    /// 时间：2017-06-21 
    /// </summary>
    public class NDownList : Control
    {
        private int minimum;
        private int maximum;
        private int m_last_index;
        private int m_vScroll_pos;
        private string m_last_tooltip;
        private ToolTip ToolTip;
        private int _selectedIndex;
        private int _itemHeight;
        private bool _visible;
        private bool _formattingEnabled;
        private BorderStyle _borderStyle;
        private DrawMode _drawMode;
        private NDownListItem _selectedItem;
        private NDownListItemCollection _items;
        private VScrollBar m_vScroll;
        private IContainer components;

        public int SelectedIndex
        {
            get
            {
                return this._selectedIndex;
            }
            set
            {
                this._selectedIndex = value;
                this.MeasureScrollPos();
            }
        }

        public int ItemHeight
        {
            get
            {
                return this._itemHeight;
            }
            set
            {
                this._itemHeight = value;
            }
        }

        public bool FormattingEnabled
        {
            get
            {
                return this._formattingEnabled;
            }
            set
            {
                this._formattingEnabled = value;
            }
        }

        public new bool Visible
        {
            get
            {
                return _visible;
            }
            set
            {
                if (_visible != value)
                {
                    _visible = value;                   
                    base.Visible = _visible;
                    this.MeasureScrollPos();
                }
            }
        }

        public BorderStyle BorderStyle
        {
            get
            {
                return this._borderStyle;
            }
            set
            {
                this._borderStyle = value;
            }
        }

        public DrawMode DrawMode
        {
            get
            {
                return this._drawMode;
            }
            set
            {
                this._drawMode = value;
            }
        }

        public NDownListItem SelectedItem
        {
            get
            {
                return this._selectedItem;
            }
            set
            {
                this._selectedItem = value;
                if (this._selectedItem == null)
                    return;
                this.SelectedIndex = this._selectedItem.Index;
            }
        }

        public NDownListItemCollection Items
        {
            get
            {
                return this._items;
            }
            set
            {
                this._items = value;
                this.Invalidate();
            }
        }

        public VScrollBar VScrollBar
        {
            get
            {
                return this.m_vScroll;
            }
            set
            {
                this.m_vScroll = value;
            }
        }

        public NDownList()
        {
            this.components = (IContainer)new System.ComponentModel.Container();
            this.minimum = 0;
            this.maximum = 100;
            this.m_last_index = -1;
            this.m_vScroll_pos = 0;
            this.m_last_tooltip = string.Empty;
            this.ToolTip = new ToolTip(components);
            this.InitializeComponent();
            this.Initialize();
        }

        private void Initialize()
        {
            this.SelectedIndex = -1;
            this.ItemHeight = 24;
            this.Visible = true;
            this.Items = new NDownListItemCollection(this);
            this.BorderStyle = BorderStyle.FixedSingle;
            this.BackColor = SystemColors.Control;
            this.DrawMode = DrawMode.OwnerDrawVariable;            
            if (this.components != null)
                this.ToolTip = new ToolTip(this.components);
            this.AddScroolBars();
            this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true);
            this.UpdateStyles();
        }

        private void AddScroolBars()
        {
            this.m_vScroll = new VScrollBar();
            this.m_vScroll.SetBounds(this.Width - 21, 1, 20, this.Height - 2);
            this.m_vScroll.SmallChange = 24;
            this.m_vScroll.Visible = false;             
            this.m_vScroll.Scroll += new ScrollEventHandler(OnVScroll);
            this.Controls.Add((Control)this.m_vScroll);
        }

        public void MeasureScrollBar()
        {
            if (this.Items == null || this.Items.Count <= 0 || this.m_vScroll == null)
                return;
            this.m_vScroll.Minimum = this.minimum;
            if (this.Height > 0)
            {
                if (this.Items.Count * this.ItemHeight > this.Height)
                {
                    this.maximum = this.Items.Count * this.ItemHeight % this.Height != 0 ? (this.Items.Count + 1) * this.ItemHeight - this.Height : this.Items.Count * this.ItemHeight - this.Height;
                    this.m_vScroll.Visible = true;
                    this.m_vScroll.SetBounds(this.Width - 21, 1, 20, this.Height - 2);
                }
                else
                {
                    this.m_vScroll_pos = 0;
                    this.m_vScroll.Value = 0;
                    this.m_vScroll.Visible = false;
                }
            }
            else
            {
                this.m_vScroll_pos = 0;
                this.m_vScroll.Value = 0;
                this.m_vScroll.Visible = false;
            }            
            this.m_vScroll.Maximum = this.maximum;
        }

        public void MeasureScrollPos()
        {
            if (this.VScrollBar == null || !this.VScrollBar.Visible || this.SelectedIndex * this.ItemHeight < this.Height - this.ItemHeight)
                return;
            int oldValue = this.VScrollBar.Value;            
            int newValue = (this.SelectedIndex + 1) * this.ItemHeight - this.Height;
            if (newValue < minimum) newValue = minimum;
            if (newValue > maximum) newValue = maximum;
            this.VScrollBar.Value = newValue;
            this.OnVScroll((object)this, new ScrollEventArgs(ScrollEventType.SmallDecrement, oldValue, newValue, ScrollOrientation.VerticalScroll));
        }

        private void ResetScrollPos()
        {
            if (this.IsHandleCreated)
            {
                this.m_vScroll_pos = 0;
                this.VScrollBar.Value = 0;
            }
        }

        private void OnVScroll(object sender, ScrollEventArgs e)
        {
            this.m_vScroll_pos += -(e.NewValue - e.OldValue);
            this.Invalidate();
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            this.Focus();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            if (!this.VScrollBar.Visible)
                return;
            int num1 = -e.Delta / this.ItemHeight;
            if (this.VScrollBar.Value + num1 < this.VScrollBar.Minimum || this.VScrollBar.Value + num1 > this.VScrollBar.Maximum)
                return;
            int oldValue = this.VScrollBar.Value;
            int num2 = oldValue + num1;
            VScrollBar vscrollBar = this.VScrollBar;
            int num3 = vscrollBar.Value + num1;
            vscrollBar.Value = num3;
            this.OnVScroll((object)this, new ScrollEventArgs(ScrollEventType.SmallDecrement, oldValue, this.VScrollBar.Value));
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            NDownListItem itemFromPoint = this.FindItemFromPoint(new Point(e.X, e.Y + Math.Abs(this.m_vScroll_pos)));
            if (itemFromPoint == null)
            {
                this.m_last_tooltip = "";
                this.ToolTip.RemoveAll();
            }
            else
            {
                if (this.m_last_index == itemFromPoint.Index && this.m_last_tooltip == itemFromPoint.Text)
                    return;
                this.ToolTip.SetToolTip((Control)this, itemFromPoint.Text);
                this.m_last_tooltip = itemFromPoint.Text;
                this.m_last_index = itemFromPoint.Index;
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this.MeasureScrollBar();
            this.ResetScrollPos();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics graphics = e.Graphics;
            for (int index = 0; index < this.Items.Count; ++index)
            {
                if (index == this.SelectedIndex)
                    this.DrawItem(new DrawItemEventArgs(graphics, this.Font, new Rectangle(0, index * this.ItemHeight + this.m_vScroll_pos, this.Width, this.ItemHeight), index, DrawItemState.Selected, Color.White, Color.Blue));
                else
                    this.DrawItem(new DrawItemEventArgs(graphics, this.Font, new Rectangle(0, index * this.ItemHeight + this.m_vScroll_pos, this.Width, this.ItemHeight), index, DrawItemState.Default, Color.Black, Color.Empty));
            }
            ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, SystemColors.ControlDark, 1, ButtonBorderStyle.Solid, SystemColors.ControlDark, 1, ButtonBorderStyle.Solid, SystemColors.ControlDark, 1, ButtonBorderStyle.Solid, SystemColors.ControlDark, 1, ButtonBorderStyle.Solid);
        }

        protected void DrawItem(DrawItemEventArgs e)
        {
            if (e.Index == -1 || e.Index >= this.Items.Count)
                return;
            int index = e.Index;
            Graphics graphics = e.Graphics;
            Rectangle bounds1 = e.Bounds;
            NDownListItem ndownListItem = this.Items[index];
            StringFormat stringFormat = new StringFormat();
            stringFormat.LineAlignment = StringAlignment.Center;
            stringFormat.Alignment = StringAlignment.Center;
            if (e.Index % 2 == 0)
                graphics.FillRectangle((Brush)new SolidBrush(SystemColors.ControlLight), e.Bounds);
            else
                graphics.FillRectangle((Brush)new SolidBrush(Color.WhiteSmoke), e.Bounds);
            if (this.VScrollBar.Visible)
            {
                // ISSUE: explicit reference operation
                // ISSUE: variable of a reference type
                Rectangle local = @bounds1;
                int width1 = e.Bounds.Width;
                Rectangle bounds2 = e.Bounds;
                int y = bounds2.Y;
                bounds2 = e.Bounds;
                int width2 = bounds2.Width - this.VScrollBar.Width;
                bounds2 = e.Bounds;
                int height = bounds2.Height;
                // ISSUE: explicit reference operation
                local = new Rectangle(width1, y, width2, height);
            }
            Rectangle rect1 = new Rectangle(4, bounds1.Y + 4, 16, bounds1.Height - 8);
            Rectangle bounds3 = new Rectangle(bounds1.Width - 50, bounds1.Y + 2, 50, bounds1.Height - 4);
            if (m_vScroll.Visible)
            {
                bounds3 = new Rectangle(bounds1.Width - 50 - m_vScroll.Width, bounds1.Y + 2, 50, bounds1.Height - 4);
            }           
            Rectangle rectangle = new Rectangle(24, bounds1.Y + 2, bounds1.Width - bounds3.Width - 24, bounds1.Height - 4);
            string text1 = ndownListItem.Text;
            Color color1 = Color.FromArgb(86, 176, 227);
            Color color2 = Color.FromArgb(230, 247, (int)byte.MaxValue);
            Color color3 = Color.FromArgb(86, 176, 227);
            Color color4 = Color.FromArgb(160, 160, 160);
            string text2 = ndownListItem.ProgressBar.Value == 100 ? (e.Index + 1).ToString() + ": " + ndownListItem.Name + " 下载完成" : (e.Index + 1).ToString() + ": 正在下载 " + ndownListItem.Name;
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                if (ndownListItem.ProgressBar.Value != 100)
                {
                    graphics.FillEllipse((Brush)new SolidBrush(color1), rect1);
                }
                else
                {
                    graphics.FillEllipse((Brush)new SolidBrush(color1), rect1);
                    graphics.DrawImage((Image)Resources.success, rect1);
                }
                graphics.SmoothingMode = SmoothingMode.Default;
                if (ndownListItem.ProgressBar.Value != 0 && ndownListItem.ProgressBar.Value != 100)
                {
                    graphics.FillRectangle((Brush)new SolidBrush(color2), rectangle);
                    Rectangle rect2 = new Rectangle(rectangle.X, rectangle.Y, (int)((double)ndownListItem.ProgressBar.Value * 1.0 / 100.0 * (double)rectangle.Width), rectangle.Height);
                    graphics.FillRectangle((Brush)new SolidBrush(color3), rect2);
                    graphics.DrawRectangle(new Pen(color4), rectangle);
                }
                TextRenderer.DrawText((IDeviceContext)graphics, text2, this.Font, rectangle, Color.Black, TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter);
                TextRenderer.DrawText((IDeviceContext)graphics, ndownListItem.StateLabel.Text, this.Font, bounds3, Color.Black, TextFormatFlags.EndEllipsis | TextFormatFlags.Right | TextFormatFlags.VerticalCenter);
            }
            else
            {
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                if (ndownListItem.ProgressBar.Value == 100)
                {
                    graphics.FillEllipse((Brush)new SolidBrush(color1), rect1);
                    graphics.DrawImage((Image)Resources.success, rect1);
                }
                else
                    graphics.DrawEllipse(new Pen(color1, 1f), rect1);
                graphics.SmoothingMode = SmoothingMode.Default;
                if (ndownListItem.ProgressBar.Value != 0 && ndownListItem.ProgressBar.Value != 100)
                {
                    graphics.FillRectangle((Brush)new SolidBrush(color2), rectangle);
                    Rectangle rect2 = new Rectangle(rectangle.X, rectangle.Y, (int)((double)ndownListItem.ProgressBar.Value * 1.0 / 100.0 * (double)rectangle.Width), rectangle.Height);
                    graphics.FillRectangle((Brush)new SolidBrush(color3), rect2);
                    graphics.DrawRectangle(new Pen(color4), rectangle);
                }
                TextRenderer.DrawText((IDeviceContext)graphics, text2, this.Font, rectangle, Color.Black, TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter);
                TextRenderer.DrawText((IDeviceContext)graphics, ndownListItem.StateLabel.Text, this.Font, bounds3, Color.Black, TextFormatFlags.EndEllipsis | TextFormatFlags.Right | TextFormatFlags.VerticalCenter);
            }
        }

        protected NDownListItem FindItemFromPoint(Point pt)
        {
            for (int index = 0; index < this.Items.Count; ++index)
            {
                if (new Rectangle(24, index * this.ItemHeight, this.Width - 74, this.ItemHeight).Contains(pt))
                    return this.Items[index];
            }
            return (NDownListItem)null;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && this.components != null)
                this.components.Dispose();
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.components = (IContainer)new Container();
            this.Name = "NDownList";
            this.Size = new Size(196, 216);
            this.ResumeLayout(false);
        }

    }
}
